﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Compilation;
using System.Web.Routing;

namespace YmtAuth.Web
{
    public class GenericHandlerRoute<T> : RouteBase,IRouteHandler where T : IHttpHandler, new()
    {
        public string RouteUrl { get; set; }
        

        public GenericHandlerRoute(string routeUrl)
        {
            RouteUrl = routeUrl;
        }


        public override RouteData GetRouteData(HttpContextBase httpContext)
        {
            // See if the current request matches this route's url
            string baseUrl = httpContext.Request.CurrentExecutionFilePath;
            int ix = baseUrl.IndexOf(RouteUrl);
            if (ix == -1)
                // Doesn't match this route.  Returning null indicates to the asp.net runtime that this route doesn't apply for the current request.
                return null;

            baseUrl = baseUrl.Substring(0, ix + RouteUrl.Length);

            // This is kind of a hack.  There's no way to access the route data (or even the route url) from an IHttpHandler (which has a very basic interface).
            // We need to store the "base" url somewhere, including parts of the route url that are constant, like maybe the name of a method, etc.
            // For instance, if the route url "myService/myMethod/{myArg}", and the request url were "http://localhost/myApp/myService/myMethod/argValue",
            // the "current execution path" would include the "myServer/myMethod" as part of the url, which is incorrect (and it will prevent your UriTemplates from matching).
            // Since at this point in the exectuion, we know the route url, we can calculate the true base url (excluding all parts of the route url).
            // This means that any IHttpHandlers that use this routing mechanism will have to look for the "__baseUrl" item in the HttpContext.Current.Items bag.
            // TODO: Another way to solve this would be to create a subclass of IHttpHandler that has a BaseUrl property that can be set, and only let this route handler
            // work with instances of the subclass.  Perhaps I can just have RestHttpHandler have that property.  My reticence is that it would be nice to have a generic
            // route handler that works for any "plain ol" IHttpHandler (even though in this case, you have to use the "global" base url that's stored in HttpContext.Current.Items...)
            // Oh well.  At least this works for now.
            httpContext.Items["__baseUrl"] = baseUrl;
            YmtSystem.CrossCutting.YmatouLoggingService.Debug("request url {0}", baseUrl);
            GenericHandlerRouteHandler<T> routeHandler = new GenericHandlerRouteHandler<T>();
            RouteData rdata = new RouteData(this, routeHandler);

            return rdata;
        }


        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
            // This route entry doesn't generate outbound Urls.
            return null;
        }

        public IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            return new GenericHandlerRouteHandler<T>().GetHttpHandler(requestContext);
        }
    }
    public class GenericHandlerRouteHandler<T> : IRouteHandler where T : IHttpHandler, new()
    {
        public IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            return new T();
        }
    }
    public class HttpHandlerRouteHandler : IRouteHandler
    {

        private string _VirtualPath;

        public HttpHandlerRouteHandler(string virtualPath)
        {
            this._VirtualPath = virtualPath;
        }

        public IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            return (IHttpHandler)BuildManager.CreateInstanceFromVirtualPath(this._VirtualPath, typeof(IHttpHandler));
        }

    }
}